package analyser.node.v1;

import analyser.node.AbstractNodeAnalyser;
import kit.AnalyserIndexerKit;
import kit.LetterIndexer;
import model.v1.MibObjectTypeNodeV1;
import util.common.CharType;
import util.common.MibKeys;
import util.common.StringUtils;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

public class MibObjectTypeV1Analyser extends AbstractNodeAnalyser<MibObjectTypeNodeV1> {
    protected MibObjectTypeNodeV1 node2;

    public MibObjectTypeV1Analyser(List<String> txtList) {
        super(txtList);
        node = node2 = new MibObjectTypeNodeV1();
    }

    @Override
    protected void doAnalyse() {
        String str = null;
        String identify = null;
        int state = 1;
        while (state != 99){
            switch (state){
                case 1:
                    str = indexer.getNextToSpaceIgnoreLeftSpace();
                    if ((state = kit.notNull(str, 2, -state)) == 2){
                        node2.name = str;
                    }
                    break;
                case 2:
                    state = kit.nextMatch(MibKeys.OBJECT_TYPE, 3, -state);
                    break;
                case 3: //Syntax模块
                    state = this.analyseSyntax(7,-3);
                    break;
                case 7: // ACCESS
                    if ((state = kit.nextMatch(MibKeys.ACCESS, 8, -7)) == 8){
                        str = indexer.getNextIgnoreLeftSpace(CharType.Letter, CharType.Hyphen);
                        if ((state = kit.notNull(str, 8, -7)) == 8){
                            node2.access = str;
                        }
                    }
                    break;
                case 8: // STATUS
                    if ((state = kit.nextMatch(MibKeys.STATUS, 9, -8)) == 9){
                        node2.status = str = indexer.getNextIgnoreLeftSpace(CharType.Letter);
                        state = kit.notNull(str, 9, -8);
                    }
                    break;
                case 9: // DESCRIPTION
                    if (indexer.isNextMatchIgnoreLeftSpace(MibKeys.DESCRIPTION)){
                        node2.description = str = this.extractAndAnalyseFormatText();
                    }
                    state = 11;
                    break;
                case 11: // REFERENCE
                    if (indexer.isNextMatchIgnoreLeftSpace(MibKeys.REFERENCE)){
                        node2.reference = str = this.extractAndAnalyseFormatText();
                    }
                    state = 13;
                    break;
                case 12:
                    state = -12;
                    break;
                case 13:
                    state = kit.nextMatch(MibKeys.INDEX, 14, 18);
                    break;
                case 14:
                    state = analyseIndexPart(15, -state);
                    break;
                case 15:
                    state = 18;
                    break;
                case 18:
                    state = kit.nextMatch(MibKeys.DEFVAL, 19, 20);
                    break;
                case 19:
                    if ((state = kit.nextMatch("{", 20, -19)) == 20){
                        if ((state = analyseDefvalPart(20, -state)) == 20){
                            state = kit.nextMatch("}", 20, -19);
                        }
                    }
                    break;
                case 20: // ::=
                    state = kit.nextMatch(MibKeys.ASSIGNMENT, 21, -state);
                    break;
                case 21: // {console 1}
                    this.analyseLeaf();
                    state = 99;
                    break;
                default:
                    kit.ThrowAnalysisException("节点ObjectType解析失败。", state, str);
            }
        }
        return;
    }

    private int  analyseDefvalPart(int success, int fail) {
        String str = null;
        int state = 1;
        MibObjectTypeNodeV1.DefValPart defValPart = node2.defValPart = new MibObjectTypeNodeV1.DefValPart();
        while (state != 99){
            switch (state){
                case 1:
                    if ((state = kit.nextMatch("{", 2, -state)) == 2)
                        defValPart.bitsValue = new LinkedList<>();
                    else{
                        str = indexer.getNextIgnoreLeftSpace(CharType.Hyphen, CharType.Number, CharType.Letter);
                        if ((state = kit.notNull(str, 5, -state)) == 5){
                            defValPart.defvalue = str;
                        }
                    }
                    break;
                case 2:
                    str = indexer.getNextIgnoreLeftSpace(CharType.Number, CharType.Letter, CharType.Hyphen);
                    if ((state = kit.notNull(str, 3, 4)) == 3){
                        defValPart.bitsValue.add(str);
                    }
                    break;
                case 3:
                    state = kit.nextMatch(",", 2, 4);
                    break;
                case 4:
                    state = kit.nextMatch("}", 5, -state);
                    break;
                case 5:
                    state = 99;
                    break;
                default:
                    return fail;
            }
        }
        return success;
    }

    private int analyseIndexPart(int success, int fail) {
        String str = null;
        boolean implied = false;
        int state = 1;
        while (state != 99){
            switch (state){
                case 1:
                    state = kit.nextMatch("{", 2, -state);
                    node2.indexTypes = new ArrayList<>();
                    break;
                case 2:
                    implied = indexer.isNextMatchIgnoreLeftSpace(MibKeys.IMPLIED);
                    state = 3;
                    break;
                case 3:
                    str = indexer.getNextIgnoreLeftSpace(CharType.Letter, CharType.Number);
                    if ((state = kit.notNull(str, 4, -state)) == 4){
                        if (implied){
                            str = MibKeys.IMPLIED + " " + str;
                        }
                        node2.indexTypes.add(str);
                    }
                    break;
                case 4:
                    if ((state = kit.nextMatch(",", 2, -4)) == -4){
                        state = kit.nextMatch("}", 5, -4);
                    }
                    break;
                case 5:
                    state = 99;
                    break;
                default:
                    return fail;
            }
        }
        return success;
    }

    private int  analyseSyntax(int success, int fail) {
        String str = null;
        String identify;
        int state = 1;
        while (state != 99){
            switch (state){
                case 1:
                    state = kit.nextMatch(MibKeys.SYNTAX, 2, fail);
                    break;
                case 2: // 类型 or SEQUENCE OF
                    str = kit.matchSyntaxType();
                    if (str == null)
                        str = indexer.getNextIgnoreLeftSpace(CharType.Number, CharType.Letter);
                    if ((state = kit.notNull(str, 3, fail)) == 3){
                        if (str.equals(MibKeys.SEQUENCE)){
                            state = kit.nextMatch(MibKeys.OF, 9, fail);
                        }else if(str.equals(MibKeys.OBJECT)){
                            state = kit.nextMatch(MibKeys.IDENTIFIER, 12, fail);
                        }else{
                            node2.syntax = str;
                        }
                    }
                    break;
                case 3: // { or (
                    if((state = kit.nextMatch("{", 4, fail)) == 4){
                        node2.namedBits = new ArrayList<>();
                    }else{
                        state = kit.nextMatch("(", 7, 11);
                    }
                    break;
                case 4:
                    int next = 5;
                    identify = str = indexer.getNextIgnoreLeftSpace(CharType.Letter, CharType.Number, CharType.Hyphen);
                    if((state = kit.notNull(str, next, fail)) == next &&
                            (state = kit.nextMatch("(", next, fail)) == next){
                        str = indexer.getNextIgnoreLeftSpace(CharType.Number, CharType.Hyphen);
                        if ((state = kit.notNull(str, next, fail)) == next){
                            int num = StringUtils.toInteger(str);
                            node2.namedBits.add(new MibObjectTypeNodeV1.NamedBit(identify, num));
                            state = kit.nextMatch(")", next, fail);
                        }
                    }
                    break;
                case 5: // , or }
                    if ((state = kit.nextMatch("}", 6, fail)) == fail){
                        state = kit.nextMatch(",", 4, fail);
                    }
                    break;
                case 6:
                    state = 99;
                    break;
                case 7:
                    int counter = 1;
                    char c;
                    while(counter > 0){
                        c = indexer.getNextChar();
                        if (c == '(')
                            counter++;
                        else if (c == ')')
                            counter --;
                    }
                    state = 8;
                    break;
                case 8:
                    state = 11;
                    break;
                case 9:
                    str = indexer.getNextIgnoreLeftSpace(CharType.Hyphen, CharType.Letter, CharType.Number);
                    if ((state = kit.notNull(str, 10, fail)) == 10){
                        node2.syntax = MibKeys.OBJECT + " " + MibKeys.IDENTIFIER + " " + str;
                    }
                    break;
                case 10:
                    state = 11;
                    break;
                case 11:
                    state = 99;
                    break;
                case 12:
                    state = 11;
                    break;
                default:
                    return fail;
            }
        }
        return success;
    }
}
